home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / MAME / src / sound / sn76496.c < prev    next >
C/C++ Source or Header  |  2000-04-04  |  9KB  |  334 lines

  1. /***************************************************************************
  2.  
  3.   sn76496.c
  4.  
  5.   Routines to emulate the Texas Instruments SN76489 / SN76496 programmable
  6.   tone /noise generator. Also known as (or at least compatible with) TMS9919.
  7.  
  8.   Noise emulation is not accurate due to lack of documentation. The noise
  9.   generator uses a shift register with a XOR-feedback network, but the exact
  10.   layout is unknown. It can be set for either period or white noise; again,
  11.   the details are unknown.
  12.  
  13. ***************************************************************************/
  14.  
  15. #include "driver.h"
  16.  
  17.  
  18. #define MAX_OUTPUT 0x7fff
  19.  
  20. #define STEP 0x10000
  21.  
  22.  
  23. /* Formulas for noise generator */
  24. /* bit0 = output */
  25.  
  26. /* noise feedback for white noise mode */
  27. #define FB_WNOISE 0x12000    /* bit15.d(16bits) = bit0(out) ^ bit2 */
  28. //#define FB_WNOISE 0x14000    /* bit15.d(16bits) = bit0(out) ^ bit1 */
  29. //#define FB_WNOISE 0x28000    /* bit16.d(17bits) = bit0(out) ^ bit2 (same to AY-3-8910) */
  30. //#define FB_WNOISE 0x50000    /* bit17.d(18bits) = bit0(out) ^ bit2 */
  31.  
  32. /* noise feedback for periodic noise mode */
  33. /* it is correct maybe (it was in the Megadrive sound manual) */
  34. //#define FB_PNOISE 0x10000    /* 16bit rorate */
  35. #define FB_PNOISE 0x08000   /* JH 981127 - fixes Do Run Run */
  36.  
  37. /* noise generator start preset (for periodic noise) */
  38. #define NG_PRESET 0x0f35
  39.  
  40.  
  41. struct SN76496
  42. {
  43.     int Channel;
  44.     int SampleRate;
  45.     unsigned int UpdateStep;
  46.     int VolTable[16];    /* volume table         */
  47.     int Register[8];    /* registers */
  48.     int LastRegister;    /* last register written */
  49.     int Volume[4];        /* volume of voice 0-2 and noise */
  50.     unsigned int RNG;        /* noise generator      */
  51.     int NoiseFB;        /* noise feedback mask */
  52.     int Period[4];
  53.     int Count[4];
  54.     int Output[4];
  55. };
  56.  
  57.  
  58. static struct SN76496 sn[MAX_76496];
  59.  
  60.  
  61.  
  62. static void SN76496Write(int chip,int data)
  63. {
  64.     struct SN76496 *R = &sn[chip];
  65.  
  66.  
  67.     /* update the output buffer before changing the registers */
  68.     stream_update(R->Channel,0);
  69.  
  70.     if (data & 0x80)
  71.     {
  72.         int r = (data & 0x70) >> 4;
  73.         int c = r/2;
  74.  
  75.         R->LastRegister = r;
  76.         R->Register[r] = (R->Register[r] & 0x3f0) | (data & 0x0f);
  77.         switch (r)
  78.         {
  79.             case 0:    /* tone 0 : frequency */
  80.             case 2:    /* tone 1 : frequency */
  81.             case 4:    /* tone 2 : frequency */
  82.                 R->Period[c] = R->UpdateStep * R->Register[r];
  83.                 if (R->Period[c] == 0) R->Period[c] = R->UpdateStep;
  84.                 if (r == 4)
  85.                 {
  86.                     /* update noise shift frequency */
  87.                     if ((R->Register[6] & 0x03) == 0x03)
  88.                         R->Period[3] = 2 * R->Period[2];
  89.                 }
  90.                 break;
  91.             case 1:    /* tone 0 : volume */
  92.             case 3:    /* tone 1 : volume */
  93.             case 5:    /* tone 2 : volume */
  94.             case 7:    /* noise  : volume */
  95.                 R->Volume[c] = R->VolTable[data & 0x0f];
  96.                 break;
  97.             case 6:    /* noise  : frequency, mode */
  98.                 {
  99.                     int n = R->Register[6];
  100.                     R->NoiseFB = (n & 4) ? FB_WNOISE : FB_PNOISE;
  101.                     n &= 3;
  102.                     /* N/512,N/1024,N/2048,Tone #3 output */
  103.                     R->Period[3] = (n == 3) ? 2 * R->Period[2] : (R->UpdateStep << (5+n));
  104.  
  105.                     /* reset noise shifter */
  106.                     R->RNG = NG_PRESET;
  107.                     R->Output[3] = R->RNG & 1;
  108.                 }
  109.                 break;
  110.         }
  111.     }
  112.     else
  113.     {
  114.         int r = R->LastRegister;
  115.         int c = r/2;
  116.  
  117.         switch (r)
  118.         {
  119.             case 0:    /* tone 0 : frequency */
  120.             case 2:    /* tone 1 : frequency */
  121.             case 4:    /* tone 2 : frequency */
  122.                 R->Register[r] = (R->Register[r] & 0x0f) | ((data & 0x3f) << 4);
  123.                 R->Period[c] = R->UpdateStep * R->Register[r];
  124.                 if (R->Period[c] == 0) R->Period[c] = R->UpdateStep;
  125.                 if (r == 4)
  126.                 {
  127.                     /* update noise shift frequency */
  128.                     if ((R->Register[6] & 0x03) == 0x03)
  129.                         R->Period[3] = 2 * R->Period[2];
  130.                 }
  131.                 break;
  132.         }
  133.     }
  134. }
  135.  
  136.  
  137. WRITE_HANDLER( SN76496_0_w ) {    SN76496Write(0,data); }
  138. WRITE_HANDLER( SN76496_1_w ) {    SN76496Write(1,data); }
  139. WRITE_HANDLER( SN76496_2_w ) {    SN76496Write(2,data); }
  140. WRITE_HANDLER( SN76496_3_w ) {    SN76496Write(3,data); }
  141.  
  142.  
  143.  
  144. static void SN76496Update(int chip,INT16 *buffer,int length)
  145. {
  146.     int i;
  147.     struct SN76496 *R = &sn[chip];
  148.  
  149.  
  150.     /* If the volume is 0, increase the counter */
  151.     for (i = 0;i < 4;i++)
  152.     {
  153.         if (R->Volume[i] == 0)
  154.         {
  155.             /* note that I do count += length, NOT count = length + 1. You might think */
  156.             /* it's the same since the volume is 0, but doing the latter could cause */
  157.             /* interferencies when the program is rapidly modulating the volume. */
  158.             if (R->Count[i] <= length*STEP) R->Count[i] += length*STEP;
  159.         }
  160.     }
  161.  
  162.     while (length > 0)
  163.     {
  164.         int vol[4];
  165.         unsigned int out;
  166.         int left;
  167.  
  168.  
  169.         /* vol[] keeps track of how long each square wave stays */
  170.         /* in the 1 position during the sample period. */
  171.         vol[0] = vol[1] = vol[2] = vol[3] = 0;
  172.  
  173.         for (i = 0;i < 3;i++)
  174.         {
  175.             if (R->Output[i]) vol[i] += R->Count[i];
  176.             R->Count[i] -= STEP;
  177.             /* Period[i] is the half period of the square wave. Here, in each */
  178.             /* loop I add Period[i] twice, so that at the end of the loop the */
  179.             /* square wave is in the same status (0 or 1) it was at the start. */
  180.             /* vol[i] is also incremented by Period[i], since the wave has been 1 */
  181.             /* exactly half of the time, regardless of the initial position. */
  182.             /* If we exit the loop in the middle, Output[i] has to be inverted */
  183.             /* and vol[i] incremented only if the exit status of the square */
  184.             /* wave is 1. */
  185.             while (R->Count[i] <= 0)
  186.             {
  187.                 R->Count[i] += R->Period[i];
  188.                 if (R->Count[i] > 0)
  189.                 {
  190.                     R->Output[i] ^= 1;
  191.                     if (R->Output[i]) vol[i] += R->Period[i];
  192.                     break;
  193.                 }
  194.                 R->Count[i] += R->Period[i];
  195.                 vol[i] += R->Period[i];
  196.             }
  197.             if (R->Output[i]) vol[i] -= R->Count[i];
  198.         }
  199.  
  200.         left = STEP;
  201.         do
  202.         {
  203.             int nextevent;
  204.  
  205.  
  206.             if (R->Count[3] < left) nextevent = R->Count[3];
  207.             else nextevent = left;
  208.  
  209.             if (R->Output[3]) vol[3] += R->Count[3];
  210.             R->Count[3] -= nextevent;
  211.             if (R->Count[3] <= 0)
  212.             {
  213.                 if (R->RNG & 1) R->RNG ^= R->NoiseFB;
  214.                 R->RNG >>= 1;
  215.                 R->Output[3] = R->RNG & 1;
  216.                 R->Count[3] += R->Period[3];
  217.                 if (R->Output[3]) vol[3] += R->Period[3];
  218.             }
  219.             if (R->Output[3]) vol[3] -= R->Count[3];
  220.  
  221.             left -= nextevent;
  222.         } while (left > 0);
  223.  
  224.         out = vol[0] * R->Volume[0] + vol[1] * R->Volume[1] +
  225.                 vol[2] * R->Volume[2] + vol[3] * R->Volume[3];
  226.  
  227.         if (out > MAX_OUTPUT * STEP) out = MAX_OUTPUT * STEP;
  228.  
  229.         *(buffer++) = out / STEP;
  230.  
  231.         length--;
  232.     }
  233. }
  234.  
  235.  
  236.  
  237. static void SN76496_set_clock(int chip,int clock)
  238. {
  239.     struct SN76496 *R = &sn[chip];
  240.  
  241.  
  242.     /* the base clock for the tone generators is the chip clock divided by 16; */
  243.     /* for the noise generator, it is clock / 256. */
  244.     /* Here we calculate the number of steps which happen during one sample */
  245.     /* at the given sample rate. No. of events = sample rate / (clock/16). */
  246.     /* STEP is a multiplier used to turn the fraction into a fixed point */
  247.     /* number. */
  248.     R->UpdateStep = ((double)STEP * R->SampleRate * 16) / clock;
  249. }
  250.  
  251.  
  252.  
  253. static void SN76496_set_gain(int chip,int gain)
  254. {
  255.     struct SN76496 *R = &sn[chip];
  256.     int i;
  257.     double out;
  258.  
  259.  
  260.     gain &= 0xff;
  261.  
  262.     /* increase max output basing on gain (0.2 dB per step) */
  263.     out = MAX_OUTPUT / 3;
  264.     while (gain-- > 0)
  265.         out *= 1.023292992;    /* = (10 ^ (0.2/20)) */
  266.  
  267.     /* build volume table (2dB per step) */
  268.     for (i = 0;i < 15;i++)
  269.     {
  270.         /* limit volume to avoid clipping */
  271.         if (out > MAX_OUTPUT / 3) R->VolTable[i] = MAX_OUTPUT / 3;
  272.         else R->VolTable[i] = out;
  273.  
  274.         out /= 1.258925412;    /* = 10 ^ (2/20) = 2dB */
  275.     }
  276.     R->VolTable[15] = 0;
  277. }
  278.  
  279.  
  280.  
  281. static int SN76496_init(const struct MachineSound *msound,int chip,int clock,int volume,int sample_rate)
  282. {
  283.     int i;
  284.     struct SN76496 *R = &sn[chip];
  285.     char name[40];
  286.  
  287.  
  288.     sprintf(name,"SN76496 #%d",chip);
  289.     R->Channel = stream_init(name,volume,sample_rate,chip,SN76496Update);
  290.  
  291.     if (R->Channel == -1)
  292.         return 1;
  293.  
  294.     R->SampleRate = sample_rate;
  295.     SN76496_set_clock(chip,clock);
  296.  
  297.     for (i = 0;i < 4;i++) R->Volume[i] = 0;
  298.  
  299.     R->LastRegister = 0;
  300.     for (i = 0;i < 8;i+=2)
  301.     {
  302.         R->Register[i] = 0;
  303.         R->Register[i + 1] = 0x0f;    /* volume = 0 */
  304.     }
  305.  
  306.     for (i = 0;i < 4;i++)
  307.     {
  308.         R->Output[i] = 0;
  309.         R->Period[i] = R->Count[i] = R->UpdateStep;
  310.     }
  311.     R->RNG = NG_PRESET;
  312.     R->Output[3] = R->RNG & 1;
  313.  
  314.     return 0;
  315. }
  316.  
  317.  
  318.  
  319. int SN76496_sh_start(const struct MachineSound *msound)
  320. {
  321.     int chip;
  322.     const struct SN76496interface *intf = msound->sound_interface;
  323.  
  324.  
  325.     for (chip = 0;chip < intf->num;chip++)
  326.     {
  327.         if (SN76496_init(msound,chip,intf->baseclock[chip],intf->volume[chip] & 0xff,Machine->sample_rate) != 0)
  328.             return 1;
  329.  
  330.         SN76496_set_gain(chip,(intf->volume[chip] >> 8) & 0xff);
  331.     }
  332.     return 0;
  333. }
  334.